using System;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;

using HtmlAgilityPack;

using Penult.BNet.Halo3.Gametypes;

namespace Penult.BNet.Halo3.PlayedGames
{
    public class Game
    {
        private DateTime _gameStart;
        private GameType _gt;
        private Uri _link;
        private Map _map;
        private List<Player> _players;
        private Playlist _playlist;
        private List<Team> _teams;

        public DateTime GameStart
        {
            get { return _gameStart; }
            set { _gameStart = value; }
        }
        public GameType GameType
        {
            get { return _gt; }
            set { _gt = value; }
        }
        public Uri Link
        {
            get { return _link; }
            set { _link = value; }
        }
        public Map Map
        {
            get { return _map; }
            set { _map = value; }
        }
        public List<Player> Players
        {
            get { return _players; }
            set { _players = value; }
        }
        public Playlist Playlist
        {
            get { return _playlist; }
            set { _playlist = value; }
        }
        public List<Team> Teams
        {
            get { return _teams; }
            set { _teams = value; }
        }

        public Game(Uri gameLink)
        {
            Link = gameLink;
            PopulateObjectFromWebPage();
        }

        protected void ThrowPathException(string path)
        {
            throw new ArgumentException("There is no content at the path " + path + " in " + Link.AbsoluteUri.ToString());
        }

        protected void GetSummary(HtmlDocument doc)
        {
            string path = @"//*/ul[@class='summary']/li[1]/text()";
            HtmlNodeCollection atts = doc.DocumentNode.SelectNodes(path);

            if (atts == null)
                ThrowPathException(path);

            // Get Name of Game & Map
            HtmlNode node = atts[0];

            string[] gameAndMapName = node.InnerText.Split(new string[1] { " on " }, StringSplitOptions.None);

            if (gameAndMapName.Length > 0)
            {
                GameType = new GameType();
                GameType.Name = gameAndMapName[0];

                Map = new Map();
                Map.Name = gameAndMapName[1];
            }

            path = @"//*/ul[@class='summary']/li[4]/text()";
            atts = doc.DocumentNode.SelectNodes(path);

            if (atts == null)
                ThrowPathException(path);

            // Get Name of Playlist
            node = atts[0];

            string playlist = node.InnerText.Replace("Playlist - ", "").Replace("&nbsp;", "");

            if (playlist.Length > 0)
            {
                Playlist = new Playlist();
                Playlist.Name = playlist;
            }

            path = @"//*/ul[@class='summary']/li[5]/text()";
            atts = doc.DocumentNode.SelectNodes(path);

            if (atts == null)
                ThrowPathException(path);

            // Get Start Time of the Game
            node = atts[0];

            string time = node.InnerText.Replace("&nbsp;", "").Replace(" PST", "").Replace(" PDT", "");

            if (time.Length > 0)
            {
                GameStart = DateTime.ParseExact(time, "M/dd/yyyy, h:m tt", CultureInfo.InvariantCulture);
                GameStart = GameStart.AddHours(2);
            }

            path = @"//*/ul[@class='summary']/li[6]/text()";
            atts = doc.DocumentNode.SelectNodes(path);

            if (atts == null)
                ThrowPathException(path);
        }
        protected void GetResults(HtmlDocument doc)
        {
            string path = @"(//*/table[@class='stats'])[1]/tr[@id]";
            HtmlNodeCollection playlistRankNodes = doc.DocumentNode.SelectNodes(path);

            if (playlistRankNodes == null)
                ThrowPathException(path);

            foreach (Player p in Players)
            {
                HtmlNode node = playlistRankNodes[p.Index];

                path = @"/td[2]";
                HtmlNodeCollection placeNodes = node.SelectNodes(path);

                if (placeNodes == null)
                    ThrowPathException(path);

                path = @"/td[3]";
                HtmlNodeCollection scoreNodes = node.SelectNodes(path);

                if (scoreNodes == null)
                    ThrowPathException(path);

                node = placeNodes[0];

                string place = node.InnerText;

                if (place != "-")
                {
                    switch (place)
                    {
                        case "1st":
                            {
                                p.Place = PlaceOrder.First;
                                break;
                            }
                        case "2nd":
                            {
                                p.Place = PlaceOrder.Second;
                                break;
                            }
                        case "3rd":
                            {
                                p.Place = PlaceOrder.Third;
                                break;
                            }
                        case "4th":
                            {
                                p.Place = PlaceOrder.Fourth;
                                break;
                            }
                        case "5th":
                            {
                                p.Place = PlaceOrder.Fifth;
                                break;
                            }
                        case "6th":
                            {
                                p.Place = PlaceOrder.Sixth;
                                break;
                            }
                        case "7th":
                            {
                                p.Place = PlaceOrder.Seventh;
                                break;
                            }
                        case "8th":
                            {
                                p.Place = PlaceOrder.Eighth;
                                break;
                            }
                        case "9th":
                            {
                                p.Place = PlaceOrder.Ninth;
                                break;
                            }
                        case "10th":
                            {
                                p.Place = PlaceOrder.Tenth;
                                break;
                            }
                        case "11th":
                            {
                                p.Place = PlaceOrder.Eleventh;
                                break;
                            }
                        case "12th":
                            {
                                p.Place = PlaceOrder.Twelfth;
                                break;
                            }
                        case "13th":
                            {
                                p.Place = PlaceOrder.Thirteenth;
                                break;
                            }
                        case "14th":
                            {
                                p.Place = PlaceOrder.Fourteenth;
                                break;
                            }
                        case "15th":
                            {
                                p.Place = PlaceOrder.Fifteenth;
                                break;
                            }
                        case "16th":
                            {
                                p.Place = PlaceOrder.Sixteenth;
                                break;
                            }
                        default:
                            {
                                p.Place = PlaceOrder.None;
                                break;
                            }
                    }
                }

                node = scoreNodes[0];

                if (node.InnerText != "-")
                {
                    p.Score = Convert.ToInt32(node.InnerText);
                }
            }

            foreach (Team t in Teams)
            {
                HtmlNode node = playlistRankNodes[t.Index];

                path = @"/td[2]";
                HtmlNodeCollection placeNodes = node.SelectNodes(path);

                if (placeNodes == null)
                    ThrowPathException(path);

                string place = placeNodes[0].InnerText;

                if (place != "-")
                {
                    switch (place)
                    {
                        case "1st":
                            {
                                t.Place = PlaceOrder.First;
                                break;
                            }
                        case "2nd":
                            {
                                t.Place = PlaceOrder.Second;
                                break;
                            }
                        case "3rd":
                            {
                                t.Place = PlaceOrder.Third;
                                break;
                            }
                        case "4th":
                            {
                                t.Place = PlaceOrder.Fourth;
                                break;
                            }
                        case "5th":
                            {
                                t.Place = PlaceOrder.Fifth;
                                break;
                            }
                        case "6th":
                            {
                                t.Place = PlaceOrder.Sixth;
                                break;
                            }
                        case "7th":
                            {
                                t.Place = PlaceOrder.Seventh;
                                break;
                            }
                        case "8th":
                            {
                                t.Place = PlaceOrder.Eighth;
                                break;
                            }
                        case "9th":
                            {
                                t.Place = PlaceOrder.Ninth;
                                break;
                            }
                        case "10th":
                            {
                                t.Place = PlaceOrder.Tenth;
                                break;
                            }
                        case "11th":
                            {
                                t.Place = PlaceOrder.Eleventh;
                                break;
                            }
                        case "12th":
                            {
                                t.Place = PlaceOrder.Twelfth;
                                break;
                            }
                        case "13th":
                            {
                                t.Place = PlaceOrder.Thirteenth;
                                break;
                            }
                        case "14th":
                            {
                                t.Place = PlaceOrder.Fourteenth;
                                break;
                            }
                        case "15th":
                            {
                                t.Place = PlaceOrder.Fifteenth;
                                break;
                            }
                        case "16th":
                            {
                                t.Place = PlaceOrder.Sixteenth;
                                break;
                            }
                        default:
                            {
                                t.Place = PlaceOrder.None;
                                break;
                            }
                    }
                }
            }
        }
        protected void GetPlayerInfo(HtmlDocument doc)
        {
            string path = @"//*/div[@class='game_details_popover']";
            HtmlNodeCollection atts = doc.DocumentNode.SelectNodes(path);

            if (atts == null)
                ThrowPathException(path);

            // Get Name of Game & Map
            HtmlNode node = atts[0];
        }
        protected void GetCarnage(HtmlDocument doc)
        {
            string path = @"(//*/table[@class='stats'])[2]/tr[@id]";
            HtmlNodeCollection playlistRankNodes = doc.DocumentNode.SelectNodes(path);

            if (playlistRankNodes == null)
                ThrowPathException(path);

            foreach (Player p in Players)
            {
                HtmlNode node = playlistRankNodes[p.Index];

                path = @"/td[2]";
                HtmlNode killsNode = node.SelectSingleNode(path);

                if (killsNode == null)
                    ThrowPathException(path);

                p.Kills = Convert.ToInt32(killsNode.InnerText);

                path = @"/td[3]";
                HtmlNode assistsNode = node.SelectSingleNode(path);

                if (assistsNode == null)
                    ThrowPathException(path);

                p.Assists = Convert.ToInt32(assistsNode.InnerText);

                path = @"/td[4]";
                HtmlNode deathsNode = node.SelectSingleNode(path);

                if (deathsNode == null)
                    ThrowPathException(path);

                p.Deaths = Convert.ToInt32(deathsNode.InnerText);

                path = @"/td[6]";
                HtmlNode suicidesNode = node.SelectSingleNode(path);

                if (suicidesNode == null)
                    ThrowPathException(path);

                p.Suicides = Convert.ToInt32(suicidesNode.InnerText);

                path = @"/td[7]";
                HtmlNode betrayalsNode = node.SelectSingleNode(path);

                if (betrayalsNode == null)
                    ThrowPathException(path);

                p.Betrayals = Convert.ToInt32(betrayalsNode.InnerText);

                path = @"/td[8]";
                HtmlNode scoreNode = node.SelectSingleNode(path);

                if (scoreNode == null)
                    ThrowPathException(path);

                if (scoreNode.InnerText != "-")
                {
                    p.Score = Convert.ToInt32(scoreNode.InnerText);
                }
            }
        }
        protected void GetBreakdown(HtmlDocument doc)
        {
            //*/div[@id='ctl00_mainContent_bnetpgd_pnlOverview']/div/div/div/div/div/table/tr[@id]
        }
        protected void GetFieldStats(HtmlDocument doc)
        {
            //*/div[@id='ctl00_mainContent_bnetpgd_pnlFieldStats']/div/div/div/div/div/table/tr[@id]
        }

        protected void PopulateObjectFromWebPage()
        {
            _teams = new List<Team>();
            _players = new List<Player>();

            HtmlWeb hw = new HtmlWeb();
            HtmlDocument doc = hw.Load(Link.AbsoluteUri);

            SetupPlayersAndTeams(doc);

            GetSummary(doc);
            GetResults(doc);
            GetCarnage(doc); // Sets up the Players/Teams objects and their index numbers to help get data.
            //GetPlayerInfo(doc);
            //GetBreakdown(doc);
            //GetFieldStats(doc);
        }

        private void SetupPlayersAndTeams(HtmlDocument doc)
        {
            string path = @"(//*/table[@class='stats'])[1]/tr[@id]";
            HtmlNodeCollection playerAndTeamNodes = doc.DocumentNode.SelectNodes(path);

            if (playerAndTeamNodes == null)
                ThrowPathException(path);

            Team currentTeam = null;

            for (int i = 0; i < playerAndTeamNodes.Count; i++)
            {
                HtmlNode n = playerAndTeamNodes[i];

                HtmlNode containsChildNode = n.SelectSingleNode(@"/td/span[@class='name']/a");

                // Found a Team
                if (containsChildNode == null)
                {
                    HtmlNode child = n.SelectSingleNode(@"/td/span[@class='name']/text()");

                    // Creates a new Team
                    currentTeam = new Team();

                    currentTeam.Index = i;
                    currentTeam.Name = child.InnerText;

                    try
                    {
                        currentTeam.PrimaryColor = Color.FromName(currentTeam.Name.Replace(" Team", ""));
                    }
                    catch
                    {
                        currentTeam.PrimaryColor = Color.Black;
                    }

                    // Adds Team to Game
                    Teams.Add(currentTeam);
                }
                else
                // Found a Player
                {
                    //HtmlNode child = n.SelectSingleNode(@"/td/span[@class='name']/a");

                    // Creates a new Player
                    Player player = new Player();
                    player.Name = containsChildNode.InnerText;
                    player.Index = i;

                    // Adds Player to Game
                    Players.Add(player);

                    // If there is a team, add player to the team.
                    if (currentTeam != null)
                    {
                        player.Team = currentTeam;
                        currentTeam.Players.Add(player);
                    }
                }
            }
        }
    }
}
